float radius;
float objectID;
float objectsCount;
float2 centroid;

samplerRECT modifiedSamp;
samplerRECT origSamp;

samplerRECT hueHist;
samplerRECT satHist;
samplerRECT valHist;

#define frameWidth 320.0f
#define frameHeight 240.0f

#define medianSize 3
#define SIZE 1.0f
#define BOX_KERNEL_SIZE 5.0


/************************************************************************/
/* FIRST PASS: Convert the image to HSV then thresold the result.		*/
/************************************************************************/
float4 HSV_to_RGB (float4 hsv) 
{ 
    float4 color=0; 
    float  f,p,q,t; 
    float  h,s,v; 
    float  r=0,g=0,b=0; 
    float  i; 
 
    if (hsv[1] == 0) 
    { 
        if (hsv[2] != 0) 
        { 
            color = hsv[2]; 
        } 
    } 
    else 
    { 
        h = hsv.x * 360.0; 
        s = hsv.y; 
        v = hsv.z; 
 
        if (h == 360.0) 
        { 
            h=0; 
        } 
 
        h /=60; 
        i = floor (h); 
        f = h-i; 
        p = v * (1.0 - s);
        
        q = v * (1.0 - (s * f)); 
        t = v * (1.0 - (s * (1.0 -f))); 
 
        if (i == 0) 
        { 
            r = v; 
            g = t; 
            b = p; 
        } 
        else if (i == 1) 
        { 
            r = q;  
            g = v;  
            b = p; 
        } 
        else if (i == 2) 
        { 
            r = p; 
            g = v; 
            b = t; 
        } 
        else if (i == 3) 
        { 
            r = p; 
            g = q; 
            b = v; 
        } 
        else if (i == 4) 
        { 
            r = t; 
            g = p; 
            b = v; 
        } 
        else if (i == 5) 
        { 
            r = v; 
            g = p; 
            b = q; 
        } 
 
        color.r = r; 
        color.g = g; 
        color.b = b; 
    } 
 
    return color; 
}

void smoothing(float2 texCoord : TEXCOORD0, uniform samplerRECT origSamp,
				out float4 color : COLOR0)
{
	float4 avg = 0;
	
	//color = texRECT(origSamp, texCoord);
	
	/************************************************************************/
	/* Applying Box Filter.													*/
	/************************************************************************/
	int r = (BOX_KERNEL_SIZE - 1) / 2;
	
	for(int i=-r; i <= r; i++)
	{
		for(int j=-r; j <= r; j++)
		{
			avg += texRECT(origSamp, texCoord.st + vec2(i, j));
		}
	}
	
	color = avg / (float)(BOX_KERNEL_SIZE * BOX_KERNEL_SIZE);
	
	/************************************************************************/
	float maxColor, minColor;
	float4 hsv;
	float temp;
	
	maxColor = max(color.r, color.g);
	maxColor = max(color.b, maxColor);
	
	minColor = min(color.r, color.g);
	minColor = min(color.b, minColor);
	
	/************************************************************************/
	/* Calculate the Hue.													*/
	/************************************************************************/
	if(maxColor == minColor)
	{	
		hsv.x = 0;
	}
	else if( maxColor == color.r)
	{
		temp = 60.0f * (color.g - color.b) / (maxColor - minColor) + 360.0f;
		hsv.x = temp - 360.0f * floor(temp/360.0f);
	}
	else if( maxColor == color.g)
	{
		hsv.x = 60.0f * (color.b - color.r) / (maxColor - minColor) + 120.0f;
	}
	else if( maxColor == color.b)
	{
		hsv.x = 60.0f * (color.r - color.g) / (maxColor - minColor) + 240.0f;
	}
	
	hsv.x /= 360.0;
	
	/************************************************************************/
	/* Calculate the Saturation.											*/
	/************************************************************************/
	if(maxColor == 0.0f)
		hsv.y = 0.0f;
	else
		hsv.y = 1.0f - (minColor / maxColor);
		
	/************************************************************************/
	/* Calculate the Value (Brightness).									*/
	/************************************************************************/
	hsv.z = maxColor;
	
	color = hsv;
}

void hsvTracking(float2 texCoord : TEXCOORD0, uniform samplerRECT origSamp,
				out float4 color : COLOR0,
				uniform samplerRECT hueHist, 
				uniform samplerRECT satHist, 
				uniform samplerRECT valHist)
{
	float4 hsv = texRECT(origSamp, texCoord);
	
	/************************************************************************/
	/* Thresold the HSV.													*/
	/************************************************************************/	
	color.r = 4.0 * texRECT(hueHist, float2(18 * hsv.x, 0.5)).x  * 
		texRECT(satHist, float2(10 * hsv.y, 0.5)).x * 
		texRECT(valHist, float2(10 * hsv.z, 0.5)).x;
	
	color.g = color.r;
	color.b = color.r;
	color.a = 1.0;
}

/************************************************************************/
/* SECOND PASS: Apply the median filter on the thresolded image.		*/
/************************************************************************/
void median(float2 texCoord : TEXCOORD0,
	out float4 color : COLOR0, uniform samplerRECT modifiedSamp,
				uniform float2 centroid, uniform float radius)
{
	/*float4 c;
	float4 avg = float4(0, 0, 0, 0);
	int counter;
	
	for(int i=-medianSize; i <= medianSize; i++)
	{
		for(int j=-medianSize; j <= medianSize; j++)
		{
			c = texRECT(modifiedSamp, texCoord.xy + vec2(i/320.0f, j/240.0f));
			
			if(c.r == 1.0)
				counter++;
		}
	}
	
	if(counter > ((2*medianSize+1) * (2*medianSize+1))/2)
	{
		color = 1.0;//float4(1.0, texCoord.x, texCoord.y, 1.0);
	}
	else
	{
		color = 0.0;
	}*/

	/************************************************************************/
	/* Box Filter.															*/
	/************************************************************************/
//  	float4 avg = float4(0, 0, 0, 0);
//  	
//  	for(int i=-SIZE; i <= SIZE; i++)
//  	{
//  		for(int j=-SIZE; j <= SIZE; j++)
//  		{
//  			avg += texRECT(modifiedSamp, texCoord.xy + vec2(i, j));
//  		}
//  	}
//  	
//  	color = 1.0 * avg / ((2.0 * SIZE + 1.0) * (2.0 * SIZE + 1.0));
	
	color = texRECT(modifiedSamp, texCoord.xy);
	
	if(radius > 0.0f)
	{
		float dx = texCoord.x / frameWidth - centroid.x;
		float dy = texCoord.y / frameHeight - centroid.y;
		
		float dist = (dx*dx + dy*dy) / (float)(2.0f * radius * radius);
		float gauss = exp(-dist);
		
		color *= gauss;
	}
	
 	if(color.r < 1.0 - radius)
 		color = 0;
		
	color.g *= floor(texCoord.x+1) / frameWidth;
	color.b *= floor(texCoord.y+1) / frameHeight;
	color.a = 1.0;
}

/************************************************************************/
/* THIRD PASS: Calculate the first, second moments on the X-Direction.	*/
/************************************************************************/
void SumX(float2 fptexCoord : TEXCOORD0,
	out float4 colorO : COLOR0, uniform samplerRECT samp)
{
	/* sums a row of 160 texels [0,319] at a given row y into 2 texels.*/
	float COL=160;
	float4 texcoord;
	colorO = float4(0, 0, 0, 0);
	
	texcoord.xyzw = fptexCoord.xyxy;
	texcoord.xz -= float2(COL / 2, COL / 2 - 1);

	for (int i=0 ; i<COL ; i+=2 )
	{
		colorO += texRECT(samp, texcoord.xy );
		colorO += texRECT(samp, texcoord.zw );
		texcoord.xz += float2(2, 2);
	}
}

/************************************************************************/
/* INTERMEDIATE PASS:													*/
/************************************************************************/
void SumX2(float2 fptexCoord : TEXCOORD0,
	out float4 colorO : COLOR0, uniform samplerRECT samp)
{
	/* sums a row of 320 texels [0,319] at a given row y */
	float COL = frameWidth / 160;
	float4 texcoord;
	colorO = float4(0, 0, 0, 0);

	texcoord.xyzw = fptexCoord.xyxy;
	texcoord.xz -= float2(COL / 2, COL / 2 - 1);

	for (int i=0 ; i<COL ; i+=2 )
	{
		colorO += texRECT(samp, texcoord.xy );
		colorO += texRECT(samp, texcoord.zw );
		texcoord.xz  += float2(2, 2);
	}
}

/************************************************************************/
/* FOURTH PASS: Calculate the first, second moments on the Y-Direction.	*/
/************************************************************************/
void SumY(float2 fptexCoord : TEXCOORD0,
	out float4 colorO : COLOR0, uniform samplerRECT samp)
{
	/* sums a column of 240 texels [0,240] at col 0 */
	float COL=120;
	float4 texcoord;
	colorO = float4(0.0,0.0,0.0,0.0);

	texcoord.xyzw = fptexCoord.xyxy;
	texcoord.yw -= float2(COL / 2, COL / 2 - 1);

	for (int i=0 ; i<COL ; i+=2 ) 
	{
		colorO += texRECT(samp, texcoord.xy );
		colorO += texRECT(samp, texcoord.zw );
		texcoord.yw  += float2(2, 2);
	}
}

/************************************************************************/
/* INTERMEDIATE PASS:													*/
/************************************************************************/
void SumY2(float2 fptexCoord : TEXCOORD0, out float4 colorO : COLOR0, 
			uniform samplerRECT samp, uniform float objectID, uniform float objectsCount)
{
	/* sums a column of frameWidth / 120 texels */
	if(fptexCoord.x > objectID / objectsCount  && fptexCoord.x < objectID/objectsCount + 1)
	{
		float COL= frameHeight / 120;
		float4 texcoord;
		colorO = float4(0.0, 0.0, 0.0, 0.0);
		
		texcoord.xyzw = fptexCoord.xyxy;
		texcoord.yw -= float2(COL / 2, COL / 2 - 1);
		
		for (int i=0 ; i<COL ; i+=2 ) 
		{
			colorO += texRECT(samp, texcoord.xy );
			colorO += texRECT(samp, texcoord.zw );
			texcoord.yw  += float2(2, 2);
		}
	}
	else
		discard;
}

/************************************************************************/
/* The Technique.														*/
/************************************************************************/
technique Main
{   
	pass smooth
    {	
		VertexProgram = NULL;
        FragmentProgram = compile fp30 smoothing(origSamp);
	}
	
    pass hsv
    {	
		VertexProgram = NULL;
        FragmentProgram = compile fp30 hsvTracking(origSamp,
			hueHist, satHist, valHist);
	}
	
	pass median
    {
        VertexProgram = NULL;
        FragmentProgram = compile fp30 median(modifiedSamp, centroid, radius);
	}
	
	pass sumX1
    {
        VertexProgram = NULL;
        FragmentProgram = compile fp30 SumX(modifiedSamp);
	}
	
	pass sumX2
    {
        VertexProgram = NULL;
        FragmentProgram = compile fp30 SumX2(modifiedSamp);
	}
	
	pass sumY1
    {
        VertexProgram = NULL;
        FragmentProgram = compile fp30 SumY(modifiedSamp);
	}
	
	pass sumY2
    {
        VertexProgram = NULL;
        FragmentProgram = compile fp30 SumY2(modifiedSamp, objectID, objectsCount);
	}
}